
#include "Input.h"


Input*	Input::mInput = NULL;

Input& Input::Get()
{
	if(!mInput)
	{
		mInput = new Input();

		mInput->Init();
	}

	return *mInput;
}

Input::Input() 
{
	mDirectInput = NULL;
}

Input::~Input()
{
	if(mDirectInput)
	{
		mDirectInput->Release();
		mDirectInput = NULL;
	}
}

void Input::Kill()
{
	if(mInput)
	{
		delete mInput;
		mInput = NULL;
	}
}

BOOL CALLBACK Input::mAddJoystick( LPCDIDEVICEINSTANCE pInst,VOID* pvContext )
{

	for(int i = 0;i<INPUT_MAX_CONTROLLERS;i++)
	{
		if(Input::Get().mController[i].bInUse == false)
		{
			return Input::Get().mController[i].Init(pInst);
		}
	}

	return false;
}


bool Input::Init()
{
	if FAILED(DirectInput8Create(GetModuleHandle(NULL),DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*) &mDirectInput, NULL) )
	{
		return false;
	}

	mMouse.Init();
	mKeyboard.Init();

	if FAILED(mDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL ,mAddJoystick,NULL,DIEDFL_ATTACHEDONLY))
	{
		return false;
	}

	return true;
}

void Input::Process()
{
	mMouse.Process();
	mKeyboard.Process();

	for(int i=0; i < INPUT_MAX_CONTROLLERS;i++)
	{
		mController[i].Process();
	}
}

const Input::Mouse &Input::GetMouse() 
{
	return mMouse;
}

const Input::Keyboard &Input::GetKeyboard() 
{
	return mKeyboard;
}



Input::InputDevice::InputDevice()
{
	KeyCount = 0;
	pProcessedKeys = NULL;
	DeviceHandle = NULL;
}

Input::InputDevice::~InputDevice()
{
	if(DeviceHandle)
	{
		DeviceHandle->Release();
		DeviceHandle = NULL;
	}

	if(pProcessedKeys)
	{
		delete[] pProcessedKeys;
	}
}

void Input::InputDevice::Shutdown(void)
{
	if(DeviceHandle)
	{
		DeviceHandle->Unacquire();
		DeviceHandle->Release();

		DeviceHandle = NULL;
	}
}

bool Input::InputDevice::Process(void *pData, int DataSize)
{
	if(!DeviceHandle)	return false;

	if(DeviceHandle->GetDeviceState( DataSize, pData ))
	{
		DeviceHandle->Acquire();

		memset(pData,0,DataSize);

		memset(pProcessedKeys,0,KeyCount);

		return false;
	}

	return true;
}

Input::KeyState Input::InputDevice::GetKey(int KeyID) const
{
	assert(KeyID < KeyCount);

	return pProcessedKeys[KeyID];
}

int Input::InputDevice::GetKeyCount()	const
{
	return KeyCount;
}

void Input::InputDevice::AllocateKeys(int NoOfKeys)
{
	assert(pProcessedKeys == NULL);

	KeyCount = NoOfKeys;
	pProcessedKeys = new KeyState[KeyCount];

	for(int iKey=0;iKey < KeyCount;iKey++)
	{
		pProcessedKeys[iKey] = KeyState_NotPressed;
	}
}

void Input::InputDevice::UpdateKey(bool bPressed, KeyState *pKey)
{
	if(bPressed)
	{
		switch(*pKey)
		{
		case KeyState_NotPressed:
			{
				*pKey = KeyState_Pressed;
			}
			break;

		case KeyState_Pressed:
			{
				*pKey = KeyState_Held;
			}
			break;

		case KeyState_Held:
			{
				*pKey = KeyState_Held;
			}
			break;

		case KeyState_Released:
			{
				*pKey = KeyState_Pressed;
			}
			break;

		default:
			assert(0);
			break;
		}
	}
	else
	{
		switch(*pKey)
		{
		case KeyState_NotPressed:
			{
				*pKey = KeyState_NotPressed;
			}
			break;

		case KeyState_Pressed:
			{
				*pKey = KeyState_Released;
			}
			break;

		case KeyState_Held:
			{
				*pKey = KeyState_Released;
			}
			break;

		case KeyState_Released:
			{
				*pKey = KeyState_NotPressed;
			}
			break;

		default:
			assert(0);
			break;
		}
	}
}

Input::Mouse::Mouse()
{
	AllocateKeys(3);
}

bool Input::Mouse::Init()
{
	if FAILED(Input::Get().GetDInput()->CreateDevice(GUID_SysMouse ,&DeviceHandle ,NULL)) 										return false;
	if FAILED(DeviceHandle->SetDataFormat(&c_dfDIMouse))															return false;
	if FAILED(DeviceHandle->SetCooperativeLevel(SimpleRender::Get().GetWindow() ,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND )) 	return false;

	return true;
}

void Input::Mouse::Process (void)
{
	DIMOUSESTATE dims;

	if(InputDevice::Process(&dims, sizeof(DIMOUSESTATE)) )
	{
		for(int iKey = 0; iKey < KeyCount; iKey++)
		{
			UpdateKey(dims.rgbButtons[iKey]?true:false,&pProcessedKeys[iKey]);

			D3DXVECTOR2 t = mPosition;
			//mPosition = Game::GetMousePosition();

			if(t != mPosition)
			{
				mOldPosition = t;
			}

		}
	}
}

const D3DXVECTOR2 &Input::Mouse::GetPosition(void) const
{
	return mPosition;
}

const D3DXVECTOR2 &Input::Mouse::GetOldPosition(void) const
{
	return mOldPosition;
}




#define MAX_KEYS	(256)
#define DINPUT_KEYPRESS (0x80)

Input::Keyboard::Keyboard()
{
	AllocateKeys(MAX_KEYS);
}

bool Input::Keyboard::Init()
{
	if FAILED(Input::Get().GetDInput()->CreateDevice(GUID_SysKeyboard ,&DeviceHandle ,NULL)) 						return false;
	if FAILED(DeviceHandle->SetDataFormat(&c_dfDIKeyboard))															return false;
	if FAILED(DeviceHandle->SetCooperativeLevel(SimpleRender::Get().GetWindow() ,DISCL_NONEXCLUSIVE | DISCL_FOREGROUND)) 			return false;


	return true;
}

void Input::Keyboard::Process (void)
{
	unsigned char	RawKeys[MAX_KEYS];

	if(InputDevice::Process(&RawKeys, MAX_KEYS) )
	{
		for(int iKey = 0;iKey < KeyCount;iKey++)
		{
			UpdateKey(RawKeys[iKey]==DINPUT_KEYPRESS?true:false,&pProcessedKeys[iKey]);
		}
	}
}




Input::Controller::Controller()
{
	bInUse = false;
}

bool Input::Controller::Init(void)
{
	assert(0);

	return false;
}

char *WSTR2char(const WCHAR *p)
{
	char *q = new char[wcslen(p)];

	for(int i=0;i<(int)wcslen(p)+1;i++)
	{
		q[i] = (char)p[i];
	}

	return q;
}
bool Input::Controller::Init(LPCDIDEVICEINSTANCE pData)
{
	if FAILED(Input::Get().GetDInput()->CreateDevice(pData->guidInstance ,&DeviceHandle ,NULL))			return FALSE;
	if FAILED(DeviceHandle->SetDataFormat(&c_dfDIJoystick2))											return FALSE;
	if FAILED(DeviceHandle->SetCooperativeLevel(SimpleRender::Get().GetWindow() ,DISCL_EXCLUSIVE  | DISCL_FOREGROUND ))	return FALSE;

	//mName = pData->tszInstanceName;

	DIDEVCAPS mDevCaps;

	mDevCaps.dwSize = sizeof(DIDEVCAPS);

	DeviceHandle->GetCapabilities(&mDevCaps);

	DIPROPRANGE diprg; 
	diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
	diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
	diprg.diph.dwHow        = DIPH_DEVICE; 
	diprg.lMin              = -100; 
	diprg.lMax              = +100; 

	diprg.diph.dwObj = DIJOFS_X;    // Set the x-axis range
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_Y;    // Set the y-axis range
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_Z;    // Set the y-axis range
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_RX;    // Set the x-axis range
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_RY;    // Set the y-axis range
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_RZ;    // Set the y-axis range
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_SLIDER(0);
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_SLIDER(1);
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	diprg.diph.dwObj = DIJOFS_POV(0);
	diprg.diph.dwObj = DIJOFS_POV(1);
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	// Set the dead zone for the joystick axes (because many joysticks
	// aren't perfectly calibrated to be zero when centered).
	DIPROPDWORD dipdw; 
	dipdw.diph.dwSize       = sizeof(DIPROPDWORD); 
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
	dipdw.diph.dwHow        = DIPH_DEVICE; 
	dipdw.dwData            = 2500; // Here, 1000 = 10%

	dipdw.diph.dwObj = DIJOFS_X;    // Set the x-axis deadzone
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	dipdw.diph.dwObj = DIJOFS_Y;    // Set the y-axis deadzone
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	dipdw.diph.dwObj = DIJOFS_Z;    // Set the z-axis deadzone
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	diprg.diph.dwObj = DIJOFS_RX;    // Set the x-axis range
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	diprg.diph.dwObj = DIJOFS_RY;    // Set the y-axis range
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	diprg.diph.dwObj = DIJOFS_RZ;    // Set the y-axis range
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );



	diprg.diph.dwObj = DIJOFS_SLIDER(0);
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	diprg.diph.dwObj = DIJOFS_SLIDER(1);
	DeviceHandle->SetProperty( DIPROP_DEADZONE, &dipdw.diph );

	diprg.diph.dwObj = DIJOFS_POV(0);
	diprg.diph.dwObj = DIJOFS_POV(1);
	DeviceHandle->SetProperty( DIPROP_RANGE, &diprg.diph );

	bInUse = true;

	AllocateKeys(mDevCaps.dwButtons);

	return true;
}

void Input::Controller::Process (void)
{
	DIJOYSTATE2   dijs;      // DInput joystick state structure

	if(!bInUse)	return;

	DeviceHandle->Poll();

	if(FAILED(DeviceHandle->GetDeviceState(sizeof(DIJOYSTATE2), &dijs)))
	{
		DeviceHandle->Acquire();
	}
	else
	{
		for(int iKey = 0;iKey < KeyCount;iKey++)
		{
			UpdateKey(dijs.rgbButtons[iKey]==DINPUT_KEYPRESS?true:false,&pProcessedKeys[iKey]);
		}

		analog[0].x = (float)dijs.lX;
		analog[0].y = (float)dijs.lY;

		analog[1].x = (float)dijs.lZ;
		analog[1].y = (float)dijs.lRz;

		analog[2].x = (float)dijs.lRx;
		analog[2].y = (float)dijs.lRy;
	}
}

const Input::Controller& Input::GetController(unsigned int Index)
{
	assert(Index < INPUT_MAX_CONTROLLERS);
	return mController[Index];
}
